from tkinter import *


class Square:
    """
    date: 2018.10.18~2018.10.23
    version: v0.1
    实现方式：
        库：使用自带的tkinter。
        界面：通过生成30*30个canvas来实现整个界面坐标。
        蛇：通过修改跟canvas背景色来展现出蛇。
    未来会实现的内容：
        1. 代码组织的不够明确，GUI部分应该和蛇的逻辑控制部分分开，随时可以用其他图形方式替代tkinter。
        2. 同屏双人对战，增加蛇移动速度，增加计分。
        3. 添加网络功能使多人可以对战。
    """
    def __init__(self):
        self.direction = 'right'    # 贪吃蛇头移动的方向。
        self.star = (0, 5)          # 食物的位置。
        self.snake = [(0, 1), (0, 0)]   # 初始化蛇身体坐标。
        self.main = Tk()
        self.square = self._getSquare()
        self._layout()
        self._event()
        self._go()
        self.main.mainloop()
        pass

    def _getSquare(self, s = 30):
        """
        功能 : 创建30*30个canvas，默认颜色是black。
        :param s: 网格数量。
        :return:
        """
        squares = []
        for i in range(s):
            squares.append([])
            for j in range(s):
                squares[i].append(Canvas(bg='black', height=20, width=20))
        return squares

    def _layout(self):
        """
        功能：通过grid方法实现网格的组建布局，30*30的比率展示出来。
        :return:
        """
        self.main.focus_set()
        for i in range(len(self.square)):
            for j in range(len(self.square[i])):
                self.square[i][j].grid(row=i, column=j)

    def _event(self):
        """
        功能：将图形界面和键盘上的上下左右按键事件关联起来。
        :return:
        """
        self.main.bind(sequence="<Up>", func=self._up)
        self.main.bind(sequence="<Down>", func=self._down)
        self.main.bind(sequence="<Left>", func=self._left)
        self.main.bind(sequence="<Right>", func=self._right)

    def _changecolor(self, a, b, color):
        """
        功能：对传入的坐标修改它的颜色。
        :param a: 列。
        :param b: 行。
        :param color: 颜色。
        :return:
        """
        if color == 'red':
            self.square[a][b].config(bg = 'red')
        elif color == 'black':
            self.square[a][b].config(bg='black')
        self.square[a][b].update()

    def _go(self):
        """
        功能：这里主要是用来控制蛇的移动和蛇吃到食物会边长的效果。
        :return:
        """
        import time, random

        while 1:
            x, y = self.snake[0]
            a, b = self.star
            self._changecolor(a, b, 'red')      # 在界面上显示食物。

            # 检测蛇头的方向，并控制的移动。
            if self.direction == 'up':
                if (x - 1) >= 0:
                    self.snake.insert(0, (x - 1, y))
                    pass
            elif self.direction == 'down':
                if (x + 1) < len(self.square):
                    self.snake.insert(0, (x + 1, y))
                    pass
            elif self.direction == 'left':
                if (y - 1) >= 0:
                    self.snake.insert(0, (x, y - 1))
                    pass
            elif self.direction == 'right':
                if (y + 1) < len(self.square):
                    self.snake.insert(0, (x, y + 1))
                    pass

            # 对蛇身体的坐标修改它的背景色来显示出来。
            for i in range(len(self.snake)):
                a, b = self.snake[i]
                self._changecolor(a, b, 'red')

            # 蛇头等于食物的位置表示吃到东西了，并且食物的位置会发生变化；如果没吃到就删掉蛇尾最后一个坐标。
            if self.star != self.snake[0]:
                a, b = self.snake.pop()
            else:
                self.star = (random.randrange(0, 30), random.randrange(0, 30))
            self._changecolor(a, b, 'black')

            time.sleep(0.2)

    def _up(self, e):
        """
        功能：修改蛇头方向为上。
        :param e:
        :return:
        """
        self.direction = 'up'
        pass

    def _down(self, e):
        """
        功能：修改蛇头方向为下。
        :param e:
        :return:
        """
        self.direction = 'down'
        pass

    def _left(self, e):
        """
        功能：修改蛇头方向为左。
        :param e:
        :return:
        """
        self.direction = 'left'
        pass

    def _right(self, e):
        """
        功能：修改蛇头方向为右。
        :param e:
        :return:
        """
        self.direction = 'right'
        pass


class Square2:
    """
    date: 2018.10.18~2018.10.23
    version: v0.1
    实现方式：
        库：使用自带的tkinter。
        界面：通过生成30*30个canvas来实现整个界面坐标。
        蛇：通过修改跟canvas背景色来展现出蛇。
    未来会实现的内容：
        1. 代码组织的不够明确，GUI部分应该和蛇的逻辑控制部分分开，随时可以用其他图形方式替代tkinter。
        2. 同屏双人对战，增加蛇移动速度，增加计分。
        3. 添加网络功能使多人可以对战。
    """
    def __init__(self):
        self.direction = 'right'    # 贪吃蛇头移动的方向。
        self.star = (0, 5)          # 食物的位置。
        self.snake = [(0, 1), (0, 0)]   # 初始化蛇身体坐标。
        self.main = Tk()
        self.square = self._getSquare()
        self._layout()
        self._event()
        self._go()
        self.main.mainloop()
        pass

    def _getSquare(self, s = 30):
        """
        功能 : 创建30*30个canvas，默认颜色是black。
        :param s: 网格数量。
        :return:
        """
        squares = []
        for i in range(s):
            squares.append([])
            for j in range(s):
                squares[i].append(Canvas(bg='black', height=20, width=20))
        return squares

    def _layout(self):
        """
        功能：通过grid方法实现网格的组建布局，30*30的比率展示出来。
        :return:
        """
        self.main.focus_set()
        for i in range(len(self.square)):
            for j in range(len(self.square[i])):
                self.square[i][j].grid(row=i, column=j)

    def _event(self):
        """
        功能：将图形界面和键盘上的上下左右按键事件关联起来。
        :return:
        """
        self.main.bind("<Key>", self._up)
        # self.main.bind("<Down>", self._down)
        # self.main.bind("<Left>", self._left)
        # self.main.bind("<Right>", self._right)

    def _changecolor(self, a, b, color):
        """
        功能：对传入的坐标修改它的颜色。
        :param a: 列。
        :param b: 行。
        :param color: 颜色。
        :return:
        """
        if color == 'red':
            self.square[a][b].config(bg = 'red')
        elif color == 'black':
            self.square[a][b].config(bg='black')
        self.square[a][b].update()

    def _go(self):
        """
        功能：这里主要是用来控制蛇的移动和蛇吃到食物会边长的效果。
        :return:
        """
        import time, random

        while 1:
            x, y = self.snake[0]
            a, b = self.star
            self._changecolor(a, b, 'red')      # 在界面上显示食物。

            # 检测蛇头的方向，并控制的移动。
            if self.direction == 'up':
                if (x - 1) >= 0:
                    self.snake.insert(0, (x - 1, y))
                    pass
            elif self.direction == 'down':
                if (x + 1) < len(self.square):
                    self.snake.insert(0, (x + 1, y))
                    pass
            elif self.direction == 'left':
                if (y - 1) >= 0:
                    self.snake.insert(0, (x, y - 1))
                    pass
            elif self.direction == 'right':
                if (y + 1) < len(self.square):
                    self.snake.insert(0, (x, y + 1))
                    pass

            # 对蛇身体的坐标修改它的背景色来显示出来。
            for i in range(len(self.snake)):
                a, b = self.snake[i]
                self._changecolor(a, b, 'red')

            # 蛇头等于食物的位置表示吃到东西了，并且食物的位置会发生变化；如果没吃到就删掉蛇尾最后一个坐标。
            if self.star != self.snake[0]:
                a, b = self.snake.pop()
            else:
                self.star = (random.randrange(0, 30), random.randrange(0, 30))
            self._changecolor(a, b, 'black')

            time.sleep(0.2)

    def _up(self, event):
        """
        功能：修改蛇头方向为上。
        :param e:
        :return:
        """

        print(event.__dict__)
        # if d == 'Up':
        #     print('up')
        #     self.direction = 'up'
        # elif d == 'Down':
        #     print('down')
        #     self.direction = 'down'
        # elif d == 'Left':
        #     print('left')
        #     self.direction = 'left'
        # elif d == 'Right':
        #     print('right')
        #     self.direction = 'right'
        # print(type(event.keysym))
        pass

    def _down(self, e):
        """
        功能：修改蛇头方向为下。
        :param e:
        :return:
        """
        self.direction = 'down'
        pass

    def _left(self, e):
        """
        功能：修改蛇头方向为左。
        :param e:
        :return:
        """
        self.direction = 'left'
        pass

    def _right(self, e):
        """
        功能：修改蛇头方向为右。
        :param e:
        :return:
        """
        self.direction = 'right'
        pass


Square2()